#include "event_loop.h"
#include "event_handler.h"
#include <sys/epoll.h>
#include <sys/eventfd.h>
#include <unistd.h>
#include <stdexcept>

namespace {
constexpr int kMaxEvents = 64;
}

EventLoop::EventLoop()
    : epfd_(::epoll_create1(EPOLL_CLOEXEC)),
      wakeupFd_(::eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC)),
      threadId_(std::this_thread::get_id()) {
    if (epfd_ == -1 || wakeupFd_ == -1) {
        throw std::runtime_error("Failed to create epoll or eventfd");
    }

    epoll_event ev{};
    ev.events = EPOLLIN;
    ev.data.fd = wakeupFd_;
    if (::epoll_ctl(epfd_, EPOLL_CTL_ADD, wakeupFd_, &ev) == -1) {
        throw std::runtime_error("epoll_ctl ADD wakeupFd failed");
    }
}

EventLoop::~EventLoop() {
    ::close(wakeupFd_);
    ::close(epfd_);
}

void EventLoop::loop() {
    threadId_ = std::this_thread::get_id();  // 记录所属线程
    epoll_event events[kMaxEvents];

    while (!quitting_) {
        int n = ::epoll_wait(epfd_, events, kMaxEvents, -1);
        if (n < 0) {
            if (errno == EINTR) continue;
            throw std::runtime_error("epoll_wait failed");
        }

        for (int i = 0; i < n; ++i) {
            int fd = events[i].data.fd;
            if (fd == wakeupFd_) {
                handleWakeup();
                continue;
            }
            auto it = handlers_.find(fd);
            if (it != handlers_.end()) {
                it->second->handleEvent(events[i].events);
            }
        }

        doPendingFunctors();  // 执行跨线程投递的任务
    }
}

void EventLoop::quit() {
    quitting_ = true;
    wakeup();
}

void EventLoop::addHandler(int fd, uint32_t events, EventHandler* handler) {
    epoll_event ev{};
    ev.events = events;
    ev.data.fd = fd;
    if (::epoll_ctl(epfd_, EPOLL_CTL_ADD, fd, &ev) == -1) {
        throw std::runtime_error("epoll_ctl ADD failed");
    }
    handlers_[fd] = handler;
}

void EventLoop::updateHandler(int fd, uint32_t events) {
    epoll_event ev{};
    ev.events = events;
    ev.data.fd = fd;
    if (::epoll_ctl(epfd_, EPOLL_CTL_MOD, fd, &ev) == -1) {
        throw std::runtime_error("epoll_ctl MOD failed");
    }
}

void EventLoop::removeHandler(int fd) {
    ::epoll_ctl(epfd_, EPOLL_CTL_DEL, fd, nullptr);
    handlers_.erase(fd);
}

void EventLoop::runInLoop(std::function<void()> cb) {
    if (isInLoopThread()) {
        cb();
    } else {
        {
            std::lock_guard<std::mutex> lk(mutex_);
            pendingFunctors_.push_back(std::move(cb));
        }
        wakeup();
    }
}

void EventLoop::wakeup() {
    uint64_t one = 1;
    ::write(wakeupFd_, &one, sizeof(one));
}

void EventLoop::handleWakeup() {
    uint64_t one;
    ::read(wakeupFd_, &one, sizeof(one));
}

void EventLoop::doPendingFunctors() {
    std::vector<std::function<void()>> functors;
    {
        std::lock_guard<std::mutex> lk(mutex_);
        functors.swap(pendingFunctors_);
    }
    for (auto& fn : functors) {
        fn();
    }
}